#include "luster_string.hh"

#include <inttypes.h>
#include <stdio.h>
#include <string.h>

#include "luster_flow.hh"
#include "luster_log.hh"
#include "luster_test.hh"
#include "luster_vec.hh"

namespace luster {

void stringbuf_append_cstring(StringBuffer *buf, char const *cstring) {
	if (buf->chars_.len != 0) {
		vec_pop(&buf->chars_);
	}
	for (uintptr_t i = 0; cstring[i] != 0; ++i) {
		vec_append(&buf->chars_, cstring[i]);
	}
	vec_append(&buf->chars_, '\0');
}

void stringbuf_append_usize(StringBuffer *buf, uintptr_t x) {
	char pbuf[32];
	snprintf(pbuf, sizeof(pbuf), "%" PRIuPTR, x);
	stringbuf_append_cstring(buf, pbuf);
}

void stringbuf_append_slice(StringBuffer *buf, Slice slice) {
	if (buf->chars_.len != 0) {
		buf->chars_.len -= 1;
	}

	vec_reserve(&buf->chars_, buf->chars_.len + slice.len + 1);
	for (uintptr_t i = 0; i < slice.len; ++i) {
		buf->chars_.data[buf->chars_.len + i] = slice.data[i];
	}
	buf->chars_.data[buf->chars_.len + slice.len] = 0;
	buf->chars_.len += slice.len + 1;
}

void stringbuf_append_char(StringBuffer *buf, char c) {
	if (buf->chars_.len == 0) {
		vec_append(&buf->chars_, c);
	} else {
		buf->chars_[buf->chars_.len - 1] = c;
	}
	vec_append(&buf->chars_, '\0');
}

bool slice_eq(Slice const *slice, char const *that) {
	for_range(0, slice->len) {
		if (slice->data[it] != that[it])
			return false;

		if (that[it] == 0)
			return false;
	}
	return that[slice->len] == 0;
}

luster_TEST(StringGet) {
	StringBuffer sb;

	stringbuf_append_cstring(&sb, "hello");

	LOG_CHECK_EQ(CString{sb.chars_.data}, CString{"hello"});
}

luster_TEST(StringAppend) {
	StringBuffer sb;
	luster_OWN(sb);

	stringbuf_append_cstring(&sb, "hello, the answer is: ");
	stringbuf_append_usize(&sb, 42);

	logcheck(strcmp(sb.chars_.data, "hello, the answer is: 42") == 0);
}

luster_TEST(StringSwap) {
	StringBuffer sb;
	luster_OWN(sb);

	stringbuf_append_usize(&sb, 42);

	StringBuffer tmp;

	stringbuf_append_cstring(&tmp, "int");
	stringbuf_append_char(&tmp, ' ');
	stringbuf_append_stringbuf(&tmp, sb);
	stringbuf_append_char(&tmp, ' ');
	stringbuf_append_stringbuf(&tmp, sb);

	stringbuf_clear(&sb);
	sb = tmp;

	logcheck(strcmp(sb.chars_.data, "int 42 42") == 0);
}

} // namespace luster
